<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 5.4.2">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha256-HtsXJanqjKTc8vVQjO4YMhiqFoXkfBsjBWcX91T1jr8=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"xiaoqingming18.github.io","root":"/","images":"/images","scheme":"Muse","darkmode":false,"version":"8.15.1","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"}}</script><script src="/js/config.js"></script>

    <meta name="description" content="JAVA核心技术卷I 读书笔记📑第六章 接口、表达式与内部类[✒章节内容简介] 本章首先介绍接口，接口用来描述类应该做什么，而不指定应该如何做，一个类可以实现一个或多个接口，这是接口与抽象类最大的不同。再继续介绍lambda表达式，这是一种很简洁的用来创建将来要执行的代码块的方法，通过使用lambda表达式，可以以一种很方便、简洁的方式使用回调或可变行为的代码。内部类是定义在另一个类中的内部的类">
<meta property="og:type" content="article">
<meta property="og:title" content="JAVA核心技术卷I-读书笔记">
<meta property="og:url" content="http://xiaoqingming18.github.io/2023/04/05/JAVA%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF%E5%8D%B7I-%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/index.html">
<meta property="og:site_name" content="鸣蜩十七">
<meta property="og:description" content="JAVA核心技术卷I 读书笔记📑第六章 接口、表达式与内部类[✒章节内容简介] 本章首先介绍接口，接口用来描述类应该做什么，而不指定应该如何做，一个类可以实现一个或多个接口，这是接口与抽象类最大的不同。再继续介绍lambda表达式，这是一种很简洁的用来创建将来要执行的代码块的方法，通过使用lambda表达式，可以以一种很方便、简洁的方式使用回调或可变行为的代码。内部类是定义在另一个类中的内部的类">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://github.githubassets.com/images/icons/emoji/unicode/1f4d1.png?v8">
<meta property="og:image" content="https://github.githubassets.com/images/icons/emoji/unicode/2712.png?v8">
<meta property="og:image" content="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8">
<meta property="og:image" content="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8">
<meta property="og:image" content="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8">
<meta property="og:image" content="https://github.githubassets.com/images/icons/emoji/unicode/1f4d1.png?v8">
<meta property="article:published_time" content="2023-04-05T13:35:43.000Z">
<meta property="article:modified_time" content="2023-04-18T01:37:36.334Z">
<meta property="article:author" content="鸣蜩十七">
<meta property="article:tag" content="JAVA">
<meta property="article:tag" content="读书笔记">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://github.githubassets.com/images/icons/emoji/unicode/1f4d1.png?v8">


<link rel="canonical" href="http://xiaoqingming18.github.io/2023/04/05/JAVA%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF%E5%8D%B7I-%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"http://xiaoqingming18.github.io/2023/04/05/JAVA%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF%E5%8D%B7I-%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/","path":"2023/04/05/JAVA核心技术卷I-读书笔记/","title":"JAVA核心技术卷I-读书笔记"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>JAVA核心技术卷I-读书笔记 | 鸣蜩十七</title>
  








  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>

<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">鸣蜩十七</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">鸣蜩十七是和女朋友谈恋爱的日子</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li><li class="menu-item menu-item-schedule"><a href="/schedule/" rel="section"><i class="fa fa-calendar fa-fw"></i>日程表</a></li><li class="menu-item menu-item-sitemap"><a href="/sitemap.xml" rel="section"><i class="fa fa-sitemap fa-fw"></i>站点地图</a></li><li class="menu-item menu-item-commonweal"><a href="/404/" rel="section"><i class="fa fa-heartbeat fa-fw"></i>公益 404</a></li>
  </ul>
</nav>




</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#JAVA%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF%E5%8D%B7I-%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0"><span class="nav-text">JAVA核心技术卷I 读书笔记</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#bookmark-tabs-%E7%AC%AC%E5%85%AD%E7%AB%A0-%E6%8E%A5%E5%8F%A3%E3%80%81%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%8E%E5%86%85%E9%83%A8%E7%B1%BB"><span class="nav-text">📑第六章 接口、表达式与内部类</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#page-with-curl-6-1-%E6%8E%A5%E5%8F%A3"><span class="nav-text">📃6.1 接口</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%8E%A5%E5%8F%A3%E7%9A%84%E6%A6%82%E5%BF%B5"><span class="nav-text">接口的概念</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E8%AE%A9%E7%B1%BB%E5%AE%9E%E7%8E%B0%E6%8E%A5%E5%8F%A3"><span class="nav-text">让类实现接口</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#%E6%9C%AC%E8%8A%82%E6%8F%90%E5%88%B0%E7%9A%84%E5%8A%9F%E8%83%BD%E5%87%BD%E6%95%B0%EF%BC%9A"><span class="nav-text">本节提到的功能函数：</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%B1%9E%E6%80%A7"><span class="nav-text">接口的属性</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E9%9D%99%E6%80%81%E5%92%8C%E7%A7%81%E6%9C%89%E6%96%B9%E6%B3%95"><span class="nav-text">静态和私有方法</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E9%BB%98%E8%AE%A4%E6%96%B9%E6%B3%95"><span class="nav-text">默认方法</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E8%A7%A3%E5%86%B3%E9%BB%98%E8%AE%A4%E6%96%B9%E6%B3%95%E5%86%B2%E7%AA%81"><span class="nav-text">解决默认方法冲突</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%8E%A5%E5%8F%A3%E4%B8%8E%E5%9B%9E%E8%B0%83"><span class="nav-text">接口与回调</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Comparator%E6%8E%A5%E5%8F%A3"><span class="nav-text">Comparator接口</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%AF%B9%E8%B1%A1%E5%85%8B%E9%9A%86"><span class="nav-text">对象克隆</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#page-with-curl-6-2-lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="nav-text">📃6.2 lambda表达式</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%87%BD%E6%95%B0%E5%BC%8F%E6%8E%A5%E5%8F%A3"><span class="nav-text">函数式接口</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#page-with-curl-6-3-%E5%86%85%E9%83%A8%E7%B1%BB"><span class="nav-text">📃6.3 内部类</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%86%85%E9%83%A8%E7%B1%BB%E7%9A%84%E7%89%B9%E6%AE%8A%E8%AF%AD%E6%B3%95%E8%A7%84%E5%88%99"><span class="nav-text">内部类的特殊语法规则</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%86%85%E9%83%A8%E7%B1%BB%E6%98%AF%E5%90%A6%E6%9C%89%E7%94%A8%E3%80%81%E5%BF%85%E8%A6%81%E5%92%8C%E5%AE%89%E5%85%A8%EF%BC%88%E5%BE%85%E8%A1%A5%E5%85%85%EF%BC%89"><span class="nav-text">内部类是否有用、必要和安全（待补充）</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%B1%80%E9%83%A8%E5%86%85%E9%83%A8%E7%B1%BB"><span class="nav-text">局部内部类</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E7%94%B1%E5%A4%96%E9%83%A8%E6%96%B9%E6%B3%95%E8%AE%BF%E9%97%AE%E5%8F%98%E9%87%8F"><span class="nav-text">由外部方法访问变量</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%8C%BF%E5%90%8D%E5%86%85%E9%83%A8%E7%B1%BB"><span class="nav-text">匿名内部类</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#bookmark-tabs-%E7%AC%AC%E5%85%AB%E7%AB%A0%E6%B3%9B%E5%9E%8B%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1"><span class="nav-text">📑第八章泛型程序设计</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#8-1-%E5%AE%9A%E4%B9%89%E7%AE%80%E5%8D%95%E6%B3%9B%E5%9E%8B%E7%B1%BB"><span class="nav-text">8.1 定义简单泛型类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#8-2-%E6%B3%9B%E5%9E%8B%E6%96%B9%E6%B3%95"><span class="nav-text">8.2 泛型方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#8-3-%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8F%E7%9A%84%E9%99%90%E5%AE%9A"><span class="nav-text">8.3 类型变量的限定</span></a></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">鸣蜩十七</p>
  <div class="site-description" itemprop="description">记录我的学习、生活和恋爱日常</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">43</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">8</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">37</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://xiaoqingming18.github.io/2023/04/05/JAVA%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF%E5%8D%B7I-%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="鸣蜩十七">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="鸣蜩十七">
      <meta itemprop="description" content="记录我的学习、生活和恋爱日常">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="JAVA核心技术卷I-读书笔记 | 鸣蜩十七">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          JAVA核心技术卷I-读书笔记
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-04-05 21:35:43" itemprop="dateCreated datePublished" datetime="2023-04-05T21:35:43+08:00">2023-04-05</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-04-18 09:37:36" itemprop="dateModified" datetime="2023-04-18T09:37:36+08:00">2023-04-18</time>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <h1 id="JAVA核心技术卷I-读书笔记"><a href="#JAVA核心技术卷I-读书笔记" class="headerlink" title="JAVA核心技术卷I 读书笔记"></a>JAVA核心技术卷I 读书笔记</h1><h2 id="bookmark-tabs-第六章-接口、表达式与内部类"><a href="#bookmark-tabs-第六章-接口、表达式与内部类" class="headerlink" title=":bookmark_tabs:第六章 接口、表达式与内部类"></a><span class="github-emoji"><span>📑</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4d1.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>第六章 接口、表达式与内部类</h2><p>[<span class="github-emoji"><span>✒</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/2712.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>章节内容简介] 本章首先介绍<code>接口</code>，接口用来描述类应该做什么，而不指定应该如何做，一个类可以实现一个或多个接口，这是接口与抽象类最大的不同。再继续介绍<code>lambda表达式</code>，这是一种很简洁的用来创建将来要执行的代码块的方法，通过使用lambda表达式，可以以一种很方便、简洁的方式使用<code>回调</code>或可变行为的代码。<code>内部类</code>是定义在另一个类中的内部的类。</p>
<h3 id="page-with-curl-6-1-接口"><a href="#page-with-curl-6-1-接口" class="headerlink" title=":page_with_curl:6.1 接口"></a><span class="github-emoji"><span>📃</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>6.1 接口</h3><h4 id="接口的概念"><a href="#接口的概念" class="headerlink" title="接口的概念"></a>接口的概念</h4><p>接口不是类，而是对希望符合这个接口的类的一组需求，这和抽象类很相似，也就是接口是用来表达一个类的需求的，不需要具体实现，具体实现由实现这个接口的类来完成。</p>
<p>下面给出一个示例，Array类中的<code>sort</code>方法可以对对象数组进行排序，但是要排序的对象数组中的对象必须实现<code>Comparable</code>接口，下面是Comparable接口的代码：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Comparable</span> {</span><br><span class="line">    <span class="type">int</span> <span class="title function_">compareTo</span><span class="params">(Object other)</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>由此可见，任何实现<code>Comparable</code>接口的类都需要包含<code>compareTo</code>方法，在接口中只指出实现这个接口的类需要实现这个方法，也就是接口中的是抽象方法，这个方法的具体实现交给实现这个接口的类来完成。</p>
<p>接口中所有方法都自动是<code>public</code>方法，所以在接口中声明方法时，不必提供关键字<code>public</code>。</p>
<p>除此以外，<font color="#dd0000">接口绝不会有实例字段，但是可以包含常量</font>并且<strong>在JAVA8之前</strong>，<font color="#dd0000">接口中也绝不会实现方法</font>（现在已经可以在接口中提供其他方法了，后面会说到）。但是其他方法不能引用实例字段，因为<font color="#dd0000">接口没有实例字段。</font></p>
<p>如上所述，可以将接口看成是<font color="#dd0000">没有实例字段的抽象类。</font></p>
<h4 id="让类实现接口"><a href="#让类实现接口" class="headerlink" title="让类实现接口"></a>让类实现接口</h4><p>要让类实现某个接口需要完成下面两个步骤：</p>
<ol>
<li>将类声明为实现给定的接口。</li>
<li>对接口中的<strong>所有方法</strong>提供定义。</li>
</ol>
<p>将类声明为实现给定的接口，需要使用关键字<code>implements</code>：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Comparable</span></span><br></pre></td></tr></tbody></table></figure>
<p>下一步就是实现接口中的<strong>所有</strong>抽象方法，<code>Comparable</code>接口中只有一个用于比较的<code>compareTo</code>方法：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Comparable</span> {</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compareTo</span><span class="params">(Object otherObject)</span> {</span><br><span class="line">        <span class="type">Employee</span> <span class="variable">other</span> <span class="operator">=</span> (Employee) otherObject;</span><br><span class="line">        <span class="keyword">return</span> Double.compare(salary,other.salary);</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>在上面的代码中，我们使用了静态<code>Double.compare</code>方法。如果第一个参数小于第二个参数，它会返回一个负值，相等则返回0，否则返回正值。</p>
<p>这样我们的<code>Employee</code>对象数组就可以通过调用<code>Array.sort</code>方法进行排序了，上面的代码是通过薪水排序。</p>
<p>这里可以做的更好一些，为泛型<code>Comparable</code>接口提供一个类型参数：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Comparable</span>&lt;Employee&gt; {</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compareTo</span><span class="params">(Employee other)</span> {</span><br><span class="line">        <span class="keyword">return</span> Double.compare(salary,other.salary);</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>这样一来就不用对<code>Object</code>参数进行类型转换了。这里用到了<strong>泛型</strong>，后面会详细叙述。</p>
<h5 id="本节提到的功能函数："><a href="#本节提到的功能函数：" class="headerlink" title="本节提到的功能函数："></a>本节提到的功能函数：</h5><div class="table-container">
<table>
<thead>
<tr>
<th>API</th>
<th>原型</th>
<th>功能</th>
</tr>
</thead>
<tbody>
<tr>
<td>java.lang.Comparable<t></t></td>
<td>int compareTo(T other)</td>
<td>用这个对象与other进行比较。如果这个对象小于other<br>就返回一个负整数；如果相等就返回0；否则返回一个正整数。</td>
</tr>
<tr>
<td>java.util.Arrays</td>
<td>static void sort(Object[] a)</td>
<td>对数组a中的元素进行排序。要求数组中的元素必须属于实现了<br><code>Comparable</code>接口的类，并且元素之间是可比较的。</td>
</tr>
<tr>
<td>java.lang.Integer</td>
<td>static int compare(int x,int y)</td>
<td>如果x&lt;y返回一个负整数；相等返回0；否则返回一个正整数。</td>
</tr>
<tr>
<td>java.lang.Double</td>
<td>static int compare(double x,double y)</td>
<td>如果x&lt;y返回一个负整数；相等返回0；否则返回一个正整数。</td>
</tr>
</tbody>
</table>
</div>
<h4 id="接口的属性"><a href="#接口的属性" class="headerlink" title="接口的属性"></a>接口的属性</h4><p>接口不是类，<font color="#dd0000">不能使用<code>new</code>操作符实例化一个接口，</font>但可以声明接口的变量，并且接口的变量<strong>必须</strong>引用实现了这个接口的类的对象：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Comparable</span> <span class="variable">x</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Employee</span>();</span><br></pre></td></tr></tbody></table></figure>
<p>也可以使用<code>instanceof</code>检查一个对象是否实现了某个特定的接口：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(anObject <span class="keyword">instanceof</span> Comparable) {···};</span><br></pre></td></tr></tbody></table></figure>
<p>与类的继承一样，接口也可以<strong>扩展</strong>，假设有一个<code>Moveable</code>的接口：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Moveable</span> {</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">move</span><span class="params">(<span class="type">double</span> x,<span class="type">double</span> y)</span> {···};</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>然后可以假设一个<code>Powered</code>接口扩展<code>Moveable</code>接口：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Powered</span> <span class="keyword">extends</span> <span class="title class_">Moveable</span> {</span><br><span class="line">    <span class="type">double</span> milesPerGallon;</span><br><span class="line">    <span class="type">double</span> <span class="variable">SPEED_LIMIT</span> <span class="operator">=</span> <span class="number">95</span>；</span><br><span class="line">} </span><br></pre></td></tr></tbody></table></figure>
<p>哲理又复习了一下，<font color="#dd0000">接口不能有实例字段但是可以有常量。</font>接口中的字段总是<code>public static final</code>，可以省略。</p>
<p>与抽象类不同，一个类可以实现多个接口，只需要用逗号分割不同的接口名：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Cloneable</span>,Comparable {···};</span><br></pre></td></tr></tbody></table></figure>
<h4 id="静态和私有方法"><a href="#静态和私有方法" class="headerlink" title="静态和私有方法"></a>静态和私有方法</h4><p>在Java8中，允许在接口中增加静态方法。</p>
<p>在Java9中，接口中的方法可以是<code>private</code>。由于<font color="#dd0000">私有方法只能在接口本身的方法中使用，</font>所以只能作为接口中其他方法的辅助方法。</p>
<h4 id="默认方法"><a href="#默认方法" class="headerlink" title="默认方法"></a>默认方法</h4><p>可以为接口提供<strong>默认方法</strong>，用<code>default</code>修饰符修饰：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Comparablle</span>&lt;T&gt; {</span><br><span class="line">    <span class="keyword">default</span> <span class="type">int</span> <span class="title function_">compareTo</span><span class="params">(T other)</span> {<span class="keyword">return</span> <span class="number">0</span>;}</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>需要注意的是，<code>Comparable</code>的每一个具体实现都会覆盖这个默认方法。</p>
<p>默认方法的一个重要用法是<strong>接口演化</strong>。假设很久以前你提供了这样一个类：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bag</span> <span class="keyword">implements</span> <span class="title class_">Collection</span></span><br></pre></td></tr></tbody></table></figure>
<p>后来又为这个接口增加了一个<code>stream</code>方法。假设<code>stream</code>不是一个默认方法，那么<code>Bag</code>类将不能编译，因为它没有实现这个新方法。<font color="#dd0000">为接口增加一个非默认方法无法保证“源代码兼容”</font>。将新方法设置为默认方法就可以轻松解决这个问题。</p>
<h4 id="解决默认方法冲突"><a href="#解决默认方法冲突" class="headerlink" title="解决默认方法冲突"></a>解决默认方法冲突</h4><p>如果现在一个接口中定义了一个默认方法，然后又在超类或另一个接口中定义同名方法，Java处理的规则如下：</p>
<ol>
<li>超类优先。如果超类提供了一个具体方法，同名而且有相同参数类型的默认方法会被忽略。如果一个类扩展了一个超类同时实现了一个接口，并同时从超类和接口中继承了相同的方法，<font color="#dd0000">只会考虑超类方法，接口中默认方法被忽略。</font></li>
<li>接口冲突。如果一个接口提供了一个默认方法，另一个接口提供了一个同名而且具有相同参数类型的方法，必须覆盖这个方法来解决冲突。</li>
</ol>
<p>下面举例说明第二条接口冲突的规则：</p>
<p>假设有两个包含<code>getName</code>方法的接口：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">Person</span> {</span><br><span class="line">    <span class="keyword">default</span> <span class="title function_">getName</span><span class="params">()</span> {<span class="keyword">return</span> <span class="string">""</span>;}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Named</span> {</span><br><span class="line">    <span class="keyword">default</span> <span class="title function_">getName</span><span class="params">()</span> {<span class="keyword">return</span> getClass().getName() + <span class="string">"_"</span> + hashCode();}</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>如果有一个类同时实现了这两个接口，就需要选择两个冲突方法中的一个：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Student</span> <span class="keyword">implements</span> <span class="title class_">Person</span>,Named {</span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getName</span><span class="params">()</span> {<span class="keyword">return</span> Person.<span class="built_in">super</span>.Name();}</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<h4 id="接口与回调"><a href="#接口与回调" class="headerlink" title="接口与回调"></a>接口与回调</h4><p>这部分内容用一段代码来理解：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TimerTest</span> {</span><br><span class="line">    <span class="type">var</span> <span class="variable">listener</span> <span class="operator">=</span> nre <span class="title function_">TimePrinter</span><span class="params">()</span>;</span><br><span class="line">    <span class="type">var</span> <span class="variable">timer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Timer</span>(<span class="number">1000</span>,listener);</span><br><span class="line">    timer.start();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">TimePrinter</span> <span class="keyword">implements</span> <span class="title class_">ActionListener</span> {</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">actionPerformed</span><span class="params">(ActionEvent event)</span> {</span><br><span class="line">        System.out.println(<span class="string">"At the tone,the time is "</span></span><br><span class="line">                          + Instant.ofEpochMilli(event.getWhen()));</span><br><span class="line">        Toolkit.getDefaultToolkit().beep();</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<h4 id="Comparator接口"><a href="#Comparator接口" class="headerlink" title="Comparator接口"></a>Comparator接口</h4><p>在前面我们已经了解了，实现了<code>Comparable</code>接口的对象数组可以进行排序。例如我们可以对一个字符数组进行排序，因为<code>String</code>类实现了<code>Comparable&lt;T&gt;</code>，而且<code>String.compareTo</code>方法可以按字典顺序比较字符串。</p>
<p>现在我们希望按长度递增的顺序对字符串排序，而不是按字典顺序进行排序。为此，我们可以使用<font color="#dd0000"><code>Array.sort</code>的第二个版本，</font>有一个数组和一个<strong>比较器</strong>作为参数，比较器是实现了<code>Comparator</code>接口的类的实例：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Comparator</span>&lt;t&gt; {</span><br><span class="line">    <span class="type">int</span> <span class="title function_">compare</span><span class="params">(T first,T second)</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>要按长度比较字符串，可以如下定义一个实现<code>Comparator&lt;String&gt;</code>的类：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">LengthComparator</span> <span class="keyword">implements</span> <span class="title class_">Comparator</span>&lt;String&gt; {</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compare</span><span class="params">(String first,String second)</span> {</span><br><span class="line">        <span class="keyword">return</span> first.length() - second.length;</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>具体完成比较时，需要建立一个实例：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">var</span> <span class="variable">comp</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">LengthComparator</span>();</span><br></pre></td></tr></tbody></table></figure>
<p>要对一个数组排序，需要为<code>Array.sort</code>方法传入一个<code>LengthComparator</code>对象：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">String[] friends = {<span class="string">"Peter"</span>,<span class="string">"Paul"</span>,<span class="string">"Mary"</span>};</span><br><span class="line">Array.sort(friends,<span class="keyword">new</span> <span class="title class_">LengthComparator</span>());</span><br></pre></td></tr></tbody></table></figure>
<h4 id="对象克隆"><a href="#对象克隆" class="headerlink" title="对象克隆"></a>对象克隆</h4><p><code>Cloneable</code>接口提供了一个安全的<code>clone</code>方法：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">var</span> <span class="variable">original</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Employee</span>(<span class="string">"John Public"</span>,<span class="number">50000</span>);</span><br><span class="line"><span class="type">Employee</span> <span class="variable">copy</span> <span class="operator">=</span> original.clone();</span><br><span class="line">copy.raiseSalary(<span class="number">10</span>); <span class="comment">//original不会改变</span></span><br></pre></td></tr></tbody></table></figure>
<p>但是这样的拷贝只是<strong>浅拷贝</strong>，如果对象中包含子对象的引用，拷贝字段就会得到相同子对象的另一个引用，这样一来，原对象和克隆对象仍然会共享一些信息。想要避免这种情况，就需要进行<strong>深拷贝</strong>，<font color="#dd0000">深拷贝需要通过重写<code>clone</code>方法来进行。</font></p>
<p>需要注意的是，虽然<code>clone</code>方法是直接从<code>Object</code>类继承来的，但<font color="#dd0000">如果一个对象请求克隆，但是没有显式地实现<code>cloneable</code>接口，就会生成一个检查型异常。</font>除此之外，还需要在重写<code>clone</code>方法时将其定义为<code>public</code>。</p>
<p>综上所述，即使<code>clone</code>的默认浅拷贝实现能够满足需求，还是要实现<code>Cloneable</code>接口，将<code>clone</code>重新定义为<code>public</code>，再调用<code>super.clone()</code>。</p>
<p>下面来看创建浅拷贝的<code>clone</code>方法的一个例子：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Cloneable</span> {</span><br><span class="line">    <span class="keyword">public</span> Employee <span class="title function_">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException {</span><br><span class="line">        <span class="keyword">return</span> (Employee) <span class="built_in">super</span>.clone;</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>下面来看创建深拷贝的<code>clone</code>方法的一个例子：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Cloneable</span> {</span><br><span class="line">    <span class="keyword">public</span> Employee <span class="title function_">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedExpection {</span><br><span class="line">        <span class="type">Employee</span> <span class="variable">cloned</span> <span class="operator">=</span> (Employee) <span class="built_in">super</span>.clone();</span><br><span class="line">        <span class="comment">//下面对Employee子对象进行拷贝</span></span><br><span class="line">        cloned.hireDay = (Date) hireDay.clone();</span><br><span class="line">        <span class="keyword">return</span> cloned;</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>我们来总结一下，对于每一个类，需要确定：</p>
<ol>
<li>默认的<code>clone</code>方法能否满足需求？</li>
<li>是否可以在可变子对象上调用<code>clone</code>方法来修补默认的<code>clone</code>方法；</li>
<li>是否不该使用<code>clone</code>？</li>
</ol>
<p>实际上第3个是默认选项，如果选择第1或第2选项，类必须：</p>
<ol>
<li>实现<code>Cloneable</code>接口；</li>
<li>重新定义<code>clone</code>方法，并指定<code>public</code>访问修饰符。</li>
</ol>
<h3 id="page-with-curl-6-2-lambda表达式"><a href="#page-with-curl-6-2-lambda表达式" class="headerlink" title=":page_with_curl:6.2 lambda表达式"></a><span class="github-emoji"><span>📃</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>6.2 lambda表达式</h3><p>lambda表达式是一个可传递的代码块，可以在以后执行一次或多次，下面我们来看看哪些地方可以用到lambda表达式。</p>
<p>继续看之前说到的排序例子，我们传入代码来检查一个字符串是否比另一个字符串短，现在我们可以用lambda表达式这样写：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">(String first,String second)</span><br><span class="line">-&gt; first.length() - second.length();</span><br></pre></td></tr></tbody></table></figure>
<p>如果代码要完成的计算无法在一个表达式中完成，还可以把这些代码放在<code>{}</code>块中，并包含<code>return</code>语句，像下面这样：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">(String first,String second) -&gt; {</span><br><span class="line">    <span class="keyword">if</span>(first.length() &lt; second.length()) <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span>(first.length() &gt; second.length()) <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>如果lambda表达式没有参数，也要提供一对空括号：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">() -&gt; {<span class="keyword">for</span>(<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">100</span>;i &gt;= <span class="number">0</span>;i--)System.out.println(i);}</span><br></pre></td></tr></tbody></table></figure>
<p>如果可以推导出lambda表达式的参数类型，则可以忽略其类型.</p>
<h4 id="函数式接口"><a href="#函数式接口" class="headerlink" title="函数式接口"></a>函数式接口</h4><p>对于只有一个抽象方法的接口，需要这种接口的对象时，就可以提供一个lambda表达式，这种接口成为<strong>函数式接口</strong>。</p>
<p>为了展示如何转换为函数式接口，下面考虑<code>Arrays.sort</code>方法。它的第二个参数需要一个<code>Comparator</code>示例，<code>Comparator</code>就是只有一个方法的接口，所以可以提供一个lambda表达式：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Arrays.sort(words,</span><br><span class="line">           (first,second) -&gt; first.length() - second.length());</span><br></pre></td></tr></tbody></table></figure>
<h3 id="page-with-curl-6-3-内部类"><a href="#page-with-curl-6-3-内部类" class="headerlink" title=":page_with_curl:6.3 内部类"></a><span class="github-emoji"><span>📃</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>6.3 内部类</h3><p><strong>内部类</strong>是定义在另一个类中的类，内部类有以下特点：</p>
<ol>
<li>内部类可以对同一个包中的其他类隐藏</li>
<li>内部类方法可以访问定义这个类的作用域中的数据，包括私有数据（<font color="#dd0000">也即内部类可以访问外类数据，包括外部类的私有数据</font>）</li>
</ol>
<p>通过下面的例子简单了解一下内部类的使用：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TalkingClock</span> {</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> interval;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">boolean</span> beep;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">TalkingClock</span><span class="params">(<span class="type">int</span> interval,<span class="type">boolean</span> beep)</span> {</span><br><span class="line">        <span class="built_in">this</span>.interval = interval;</span><br><span class="line">        <span class="built_in">this</span>.beep = beep;</span><br><span class="line">    }</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">start</span><span class="params">()</span> {</span><br><span class="line">        <span class="type">var</span> <span class="variable">listener</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TimePrinter</span>();</span><br><span class="line">        <span class="type">var</span> <span class="variable">timer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Timer</span>(interval,listener);</span><br><span class="line">        time.start();</span><br><span class="line">    }</span><br><span class="line">    <span class="comment">//下面是内部类的定义</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TimePrinter</span> <span class="keyword">implements</span> <span class="title class_">ActionListener</span> {</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">actionPerformed</span><span class="params">(AcitonEvent event)</span> {</span><br><span class="line">            System.out.println(<span class="string">"At the tone,the time is "</span></span><br><span class="line">                              + Instant.ofEpochMilli(event.getWhen()));</span><br><span class="line">            <span class="keyword">if</span>(beep) Toolkit.getDefaultToolkit().beep();</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>上面的代码中，<code>TimePrinter</code>类中并没有<code>beep</code>字段，但是确仍旧可以访问该字段，这说明，<font color="#dd0000">一个内部类方法可以访问外部类的数据字段，包括私有字段。</font>为此，内部类的对象总有一个隐式引用，指向创建它的外部类对象，这个引用在内部类的定义中是不可见的。</p>
<h4 id="内部类的特殊语法规则"><a href="#内部类的特殊语法规则" class="headerlink" title="内部类的特殊语法规则"></a>内部类的特殊语法规则</h4><p>表达式<code>OuterClass.this</code>表示外部类的引用。例如，可以像下面这样编写<code>TimePrinter</code>类中的<code>actionPerformed</code>方法：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">actionPerformed</span><span class="params">(ActionEvent event)</span> {</span><br><span class="line">    ···</span><br><span class="line">    <span class="keyword">if</span>(TalkingClock.<span class="built_in">this</span>.beep) Toolkit.getDefaultTolkit.beep();</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>反过来，可以采用以下语法更加明确地编写内部类对象的构造器：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">outerObject.<span class="keyword">new</span> <span class="title class_">InnerClass</span>(construction parameters)</span><br></pre></td></tr></tbody></table></figure>
<p>例如：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ActionListener</span> <span class="variable">listener</span> <span class="operator">=</span> <span class="built_in">this</span>.<span class="keyword">new</span> <span class="title class_">TimePrinter</span>();</span><br></pre></td></tr></tbody></table></figure>
<p>在外围类的作用域之外，可以这样引用内部类：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">OuterClass.InnerClass</span><br></pre></td></tr></tbody></table></figure>
<h4 id="内部类是否有用、必要和安全（待补充）"><a href="#内部类是否有用、必要和安全（待补充）" class="headerlink" title="内部类是否有用、必要和安全（待补充）"></a>内部类是否有用、必要和安全<font color="#dd0000">（待补充）</font></h4><p>编译器会将内部类转换为常规的类文件，用<code>$</code>符号分隔外部类名与内部类名。比如<code>TalkingClock</code>类内部的<code>TimePrinter</code>类将被转换为类文件<code>TalkingClock$TimePrinter.class</code>。</p>
<p>内部类可以访问外围类的私有数据，外部类则不行。</p>
<h4 id="局部内部类"><a href="#局部内部类" class="headerlink" title="局部内部类"></a>局部内部类</h4><p>前面给的<code>TalkingClock</code>示例代码中，类型<code>TimePrinter</code>的名字只出现了一次，只是在<code>start</code>方法中创建这个类型的对象时使用了一次。当遇到这类情况时，就可以<font color="#dd0000">在一个方法中局部地定义这个类</font>：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">start</span><span class="params">()</span> {</span><br><span class="line">    <span class="keyword">class</span> <span class="title class_">TimePrinter</span> <span class="keyword">implements</span> <span class="title class_">ActionPerformed</span> {</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">actionPerformed</span><span class="params">(AcitonEvent event)</span> {</span><br><span class="line">            System.out.println(<span class="string">"At the tone,the time is "</span></span><br><span class="line">                              + Instant.ofEpochMilli(event.getWhen()));</span><br><span class="line">            <span class="keyword">if</span>(beep) Toolkit.getDefaultToolkit().beep();</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="type">var</span> <span class="variable">listner</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TimePrinter</span>();</span><br><span class="line">    <span class="type">var</span> <span class="variable">timer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Timer</span>(interval,listener);</span><br><span class="line">    timer.start();</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<font color="#dd0000">声明局部类时不能有访问说明符，局部类的作用域被限定在这个局部类的块中。</font>

<p>局部内部类有个很大的优势，即对外部世界完全隐藏，甚至<code>TalkingClock</code>类中的其他代码也不能访问它。<font color="#dd0000">除了<code>start</code>方法外，没有任何方法知道<code>TimePrinter</code>类的存在。</font></p>
<h4 id="由外部方法访问变量"><a href="#由外部方法访问变量" class="headerlink" title="由外部方法访问变量"></a>由外部方法访问变量</h4><p>局部内部类还有个优点，它们不仅能够访问外部类的字段，还可以访问局部变量！不过，<font color="#dd0000">这里的局部变量必须是<code>事实最终变量</code>，</font>这说明它们一旦赋值就不能够被改变。</p>
<p>看下面的例子，将<code>TalkingClock</code>构造器的参数<code>interval</code>和<code>beep</code>移至<code>star</code>方法：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">start</span><span class="params">(<span class="type">int</span> interval, <span class="type">boolean</span> beep)</span> {</span><br><span class="line">    <span class="keyword">class</span> <span class="title class_">TimePrinter</span> <span class="keyword">implements</span> <span class="title class_">ActionPerformed</span> {</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">actionPerformed</span><span class="params">(AcitonEvent event)</span> {</span><br><span class="line">            System.out.println(<span class="string">"At the tone,the time is "</span></span><br><span class="line">                              + Instant.ofEpochMilli(event.getWhen()));</span><br><span class="line">            <span class="keyword">if</span>(beep) Toolkit.getDefaultToolkit().beep();</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="type">var</span> <span class="variable">listner</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TimePrinter</span>();</span><br><span class="line">    <span class="type">var</span> <span class="variable">timer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Timer</span>(interval,listener);</span><br><span class="line">    timer.start();</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>我们仔细看看这段代码的控制流程：</p>
<ol>
<li>调用<code>start</code>方法。</li>
<li>调用内部类<code>TimePrinter</code>的构造器，以便初始化对象变量<code>listener</code>。</li>
<li>将<code>listener</code>引用传递给<code>Timer</code>构造器，定时器开始计时，<code>start</code>方法开始退出。此时，<code>start</code>方法的<code>beep</code>参数变量不复存在。</li>
<li>1秒之后，<code>actionPerformed</code>方法执行<code>if(beep)</code>···。</li>
</ol>
<p>为了能够让<code>actionPerformed</code>方法中的代码工作，<code>TimePrinter</code>类在<code>beep</code>参数值消失前将<code>beep</code>字段复制为<code>start</code>方法中的局部变量。</p>
<h4 id="匿名内部类"><a href="#匿名内部类" class="headerlink" title="匿名内部类"></a>匿名内部类</h4><p>使用局部内部类时， 还可以再进一步。假如只想创建这个类的一个对象，甚至不需要为类指定一个名字，这样的类被称为<strong>匿名内部类</strong>。它的语法如下：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">SuperType</span>(construction parameters) {</span><br><span class="line">    inner <span class="keyword">class</span> <span class="title class_">methods</span> and data; <span class="comment">//内部类属性和方法</span></span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>其中，<code>SuperType</code>可以是接口也可以是一个类，内部类需要实现这个接口或者继承这个类。</p>
<p>由于构造器的名字必须与类名相同，而匿名内部类没有类名，所以<font color="#dd0000">匿名内部类不能有构造器</font>。</p>
<p>下面给出一个匿名内部类的例子：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></tbody></table></figure>
<h2 id="bookmark-tabs-第八章泛型程序设计"><a href="#bookmark-tabs-第八章泛型程序设计" class="headerlink" title=":bookmark_tabs:第八章泛型程序设计"></a><span class="github-emoji"><span>📑</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4d1.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>第八章泛型程序设计</h2><h3 id="8-1-定义简单泛型类"><a href="#8-1-定义简单泛型类" class="headerlink" title="8.1 定义简单泛型类"></a>8.1 定义简单泛型类</h3><p><strong>泛型类</strong>就是有一个或多个类型变量的类，类型变量在类名后面用尖括号<code>&lt;&gt;</code>括起来：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pair</span>&lt;T&gt; {</span><br><span class="line">    <span class="keyword">private</span> T first;</span><br><span class="line">    <span class="keyword">private</span> T second;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Pair</span><span class="params">(T first,T second)</span> {</span><br><span class="line">    	<span class="built_in">this</span>.first = first;</span><br><span class="line">        <span class="built_in">this</span>.second = second;</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>如果有多个类型变量就在尖括号内部用逗号隔开：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pair</span>&lt;T,U&gt; {···}</span><br></pre></td></tr></tbody></table></figure>
<p>类型变量在类的定义中用于指定字段类型与方法返回值类型。</p>
<p>可以用具体的类型替换类型变量来实例化一个泛型类(<strong>菱形语法</strong>)：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Pair&lt;String&gt; aPair = Pair&lt;&gt;(<span class="string">"first"</span>,<span class="string">"second"</span>);</span><br></pre></td></tr></tbody></table></figure>
<h3 id="8-2-泛型方法"><a href="#8-2-泛型方法" class="headerlink" title="8.2 泛型方法"></a>8.2 泛型方法</h3><p>定义泛型方法时，将类型变量放在修饰符后面、返回类型的前面。</p>
<p>泛型方法可以在泛型类中定义，也可以在普通类中定义。</p>
<p>调用泛型方法时，将具体类型包围在尖括号内，放在方法名前面：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">middle</span> <span class="operator">=</span> ArrayAlg.&lt;String&gt;getMiddle(<span class="string">"ZXF"</span>,<span class="string">"love"</span>,<span class="string">"WJL"</span>);</span><br></pre></td></tr></tbody></table></figure>
<p>多数情况下，泛型方法调用中的类型参数可以省略，编译器可以推断出需要的类型。</p>
<h3 id="8-3-类型变量的限定"><a href="#8-3-类型变量的限定" class="headerlink" title="8.3 类型变量的限定"></a>8.3 类型变量的限定</h3>
    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/JAVA/" rel="tag"># JAVA</a>
              <a href="/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/" rel="tag"># 读书笔记</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
            </div>
            <div class="post-nav-item">
                <a href="/2023/04/09/Javasript%E9%AB%98%E7%BA%A7%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/" rel="next" title="Javasript高级程序设计(红宝书)读书笔记">
                  Javasript高级程序设计(红宝书)读书笔记 <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">鸣蜩十七</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/muse/" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>
  <div class="sidebar-dimmer"></div>
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/schemes/muse.js"></script><script src="/js/next-boot.js"></script>

  




  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>



</body>
</html>
